/*
 * Copyright (C) 2023 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <string>
#include "aki/jsbind.h"
#include "napi/native_api.h"
#include "testManager/aki_test_time.h"
#include "testResources/aki_class_cmp.h"
#include "testManager/aki_test_manager.h"
#include "testResources/akivalue_as_cmp.h"
#include "testResources/akivalue_is_cmp.h"
#include "testResources/akivalue_set_cmp.h"
#include "testResources/aki_gethandle_cmp.h"
#include "testResources/aki_arraybuffer_cmp.h"
#include "testResources/aki_globlefunction_cmp.h"
#include "testResources/akivalue_newobject_cmp.h"
#include "testResources/akivalue_callmethod_cmp.h"

#define TEST_COUNT 100000
#define TEST_NUMBER 42.0
#define ZERO 0
#define ONE 1
#define TWO 2
#define THREE 3
#define FOUR 4
#define FIVE 5
#define SIX 6
#define SEVEN 7
#define EIGHT 8

static napi_value PerformanceTestNative(napi_env env, napi_callback_info info)
{
    // NapiTest
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("NapiValueIsCheckTest",
                                                           AKITEST::AkiValueIsCmp::NapiValueIsCheckTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("NapiValueSetCheckTest",
                                                           AKITEST::AkiValueSetCmp::NapiValueSetCheckTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("NapiArrayBufferTest",
                                                           AKITEST::AkiArrayBufferCmp::NapiArrayBufferTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("NapiNewObjectTest",
                                                           AKITEST::AkiNewObjectCmp::NapiNewObjectTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("NapiCallMethodTest",
                                                           AKITEST::AkiValueCallMethod::NapiCallMethodTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("NapiValueAsCheckTest",
                                                           AKITEST_AS::AkiValueAsCmp::NapiValueAsCheckTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("NapiGetHandleCheckTest",
                                                           AKITEST_GH::AkiGetHandleCmp::NapiGetHandleCheckTest);
    
    //AkiTest
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("AkiValueIsCheckTest",
                                                           AKITEST::AkiValueIsCmp::AkiValueIsCheckTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("AkiValueSetCheckTest",
                                                           AKITEST::AkiValueSetCmp::AkiValueSetCheckTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("AkiArrayBufferTest",
                                                           AKITEST::AkiArrayBufferCmp::AkiArrayBufferTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("AkiNewObjectTest",
                                                           AKITEST::AkiNewObjectCmp::AkiNewObjectTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("AkiCallMethodTest",
                                                           AKITEST::AkiValueCallMethod::AkiCallMethodTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("AkiValueAsCheckTest",
                                                           AKITEST_AS::AkiValueAsCmp::AkiValueAsCheckTest);
    AKITEST::AkiTestManager::GetInstance().AddTestFunction("AkiGetHandleCheckTest",
                                                           AKITEST_GH::AkiGetHandleCmp::AkiGetHandleCheckTest);
    
    AKITEST::AkiTestManager::GetInstance().Start();
    AKITEST::AkiTestManager::GetInstance().PrintTestTime();
    return nullptr;
}

static napi_value GetWorkEnv(napi_env env, napi_callback_info info)
{
    AKITEST::AkiTestManager::GetInstance().SetNapiEnv(env);
    return nullptr;
}

static napi_value UpdateTestTime(napi_env env, napi_callback_info info)
{
    size_t argc = 4;
    napi_status status = napi_ok;
    napi_value args[4];
    char apiName[50];
    char moduleName[50];
    size_t apiNameSize = 0;
    size_t moduleNameSize = 0;
    int64_t testDurationNs = 0;
    int64_t akiTestTimeNs = 0;
    napi_get_cb_info(env, info, &argc, &args[ZERO], nullptr, nullptr);
    
    status = napi_get_value_string_utf8(env, args[ZERO], moduleName, sizeof(moduleNameSize), &moduleNameSize);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "UpdateTestTime", "napi_get_value_string_utf8 failed");
    }
    status = napi_get_value_string_utf8(env, args[ONE], apiName, sizeof(apiName), &apiNameSize);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "UpdateTestTime", "napi_get_value_string_utf8 failed");
    }
    status = napi_get_value_int64(env, args[TWO], &testDurationNs);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "UpdateTestTime", "napi_get_value_int64 failed");
    }
    status = napi_get_value_int64(env, args[THREE], &akiTestTimeNs);
    if (status != napi_ok) {
        OH_LOG_Print(LOG_APP, LOG_ERROR, LOG_DOMAIN, "UpdateTestTime", "napi_get_value_int64 failed");
    }
    AKITEST::AkiTestManager::GetInstance().UpdateTestTime(moduleName, apiName, testDurationNs, akiTestTimeNs);
    return nullptr;
}

namespace AKITEST_GH {
JSBIND_GLOBAL()
{
    JSBIND_FUNCTION (AkiGlobleFunction);
}
}

namespace AKITEST {
JSBIND_CLASS(AkiClassTest)
{
    JSBIND_CONSTRUCTOR<> ();
    JSBIND_METHOD (SetMsg);
    JSBIND_METHOD (GetMsg);
    JSBIND_PROPERTY (testMsg);
}
}

EXTERN_C_START
static napi_value Init(napi_env env, napi_value exports)
{
    napi_property_descriptor desc[] = {
        {"getMsg", nullptr, AKITEST::NapiClassTest::GetMsg, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"setMsg", nullptr, AKITEST::NapiClassTest::SetMsg, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"testMsg", nullptr, nullptr, AKITEST::NapiClassTest::GetMsg, AKITEST::NapiClassTest::SetMsg, nullptr,
         napi_default, nullptr}};
    napi_value constructor = nullptr;
    if (napi_define_class(env, "napiTest", NAPI_AUTO_LENGTH, AKITEST::NapiClassTest::Constructor, nullptr,
                          sizeof(desc) / sizeof(desc[0]), desc, &constructor) != napi_ok) {
        return nullptr;
    }
    if (napi_set_named_property(env, exports, "napiTest", constructor) != napi_ok) {
        return nullptr;
    }
    
    napi_property_descriptor descFunction[] = {
        {"updateTestTime", nullptr, UpdateTestTime, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"performanceTestNative", nullptr, PerformanceTestNative, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"getWorkEnv", nullptr, GetWorkEnv, nullptr, nullptr, nullptr, napi_default, nullptr},
        {"napiGFunction", nullptr, AKITEST_GH::NapiGlobleFunction, nullptr, nullptr, nullptr, napi_default, nullptr}
    };
    napi_define_properties(env, exports, sizeof(descFunction) / sizeof(descFunction[0]), descFunction);
    exports = aki::JSBind::BindSymbols(env, exports);
    return exports;
}
EXTERN_C_END

static napi_module demoModule = {
    .nm_version = 1,
    .nm_flags = 0,
    .nm_filename = nullptr,
    .nm_register_func = Init,
    .nm_modname = "entry",
    .nm_priv = ((void*)0),
    .reserved = { 0 },
};

extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
{
    napi_module_register(&demoModule);
}
